package cn.gwm.flink.streaming.strategy.termal;

import cn.gwm.flink.streaming.beans.termalRunaway.BmsTrdStrategys;
import cn.gwm.flink.streaming.beans.termalRunaway.WaringTermalDwmWithStragegyEv;
import cn.gwm.flink.streaming.beans.termalRunaway.WaringTermalWithStragegyAndFlagEv;
import cn.gwm.flink.streaming.constant.DefaultConstant;
import cn.gwm.flink.streaming.constant.TermalComparisonTypeEnum;
import cn.gwm.flink.streaming.constant.TermalProcessResult;
import cn.gwm.flink.streaming.constant.TermalRunawayTypeEnum;
import cn.gwm.utils.StreamUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.NumberUtil;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.common.state.State;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 热失控电压变化异常检测
 * @author GW00283474
 */
public class TermalVoltageVariationEvStrategy implements TermalStrategy{
    @Override
    public Dict check(State state, long timestamp) {
        try {
            ListState<WaringTermalWithStragegyAndFlagEv> listState=(ListState<WaringTermalWithStragegyAndFlagEv>)state;
            List<WaringTermalWithStragegyAndFlagEv> records = StreamUtil.convertIterable(listState.get());
            //如果没有状态值，则返回null
            if(CollectionUtil.isEmpty(records)){return null;}
            records.sort(new Comparator<WaringTermalWithStragegyAndFlagEv>() {
                @Override
                public int compare(WaringTermalWithStragegyAndFlagEv o1, WaringTermalWithStragegyAndFlagEv o2) {
                    return (int) (o1.getItem_time()- o2.getItem_time());
                }
            });
            WaringTermalWithStragegyAndFlagEv last=records.get(0);
            WaringTermalWithStragegyAndFlagEv current=records.get(1);
            BmsTrdStrategys trdStrategy = current.getBmsTrdStrategies().stream().filter(s -> TermalRunawayTypeEnum.VOLTAGEVARIATION.getKey().equals(s.getItemType())).findFirst().get();
            Dict checkDict = voltRateRulePattern(last, current, trdStrategy.getComparisonType(), new BigDecimal(trdStrategy.getThreshold()), 120);
            current.setVoltageVariationWarn(checkDict.get(TermalProcessResult.MATCH,false));
            List<WaringTermalDwmWithStragegyEv> check_records=new ArrayList<>(0);
            for(WaringTermalWithStragegyAndFlagEv s:records){
                WaringTermalDwmWithStragegyEv records_last=new WaringTermalDwmWithStragegyEv();
                BeanUtil.copyProperties(s,records_last);
                check_records.add(records_last);
            }
            checkDict.set(TermalProcessResult.CHECK_RECORDS,check_records);
            checkDict.set(TermalProcessResult.CHECK_RECORD,current);
            return checkDict;
        }catch (Exception e){
            e.printStackTrace();
        }
            return null;
    }

    /**
     * 单体电压速率下降超过0.83%/s
     */
    public static Dict voltRateRulePattern(WaringTermalWithStragegyAndFlagEv last, WaringTermalWithStragegyAndFlagEv current, int condition, BigDecimal threshold, Integer voltNum) throws Exception{
        Long duration = countDuration(last, current);
        //单体电压速率下降超过0.83%/s
        Map<String,Double> rateMap=new HashMap<String,Double>();
        List<BigDecimal> singleCellVolts=new ArrayList<>(0);
        //最近tid值
        long recentlyTid=Long.MIN_VALUE;
        recentlyTid=NumberUtil.max(last.getItem_time(),current.getItem_time(),recentlyTid);
        for(int i=1;i<=voltNum;i++){
            Object lastSingleCellVolt=last.getClass().getDeclaredField("BMS_SingleCellVolt"+i).get(last);
            Object currentSingleCellVolt=current.getClass().getDeclaredField("BMS_SingleCellVolt"+i).get(current);
            if(Objects.nonNull(lastSingleCellVolt)&&Objects.nonNull(currentSingleCellVolt)){
                BigDecimal lastSingle=(BigDecimal) lastSingleCellVolt;
                BigDecimal currentSingle=(BigDecimal)currentSingleCellVolt;
                //如果有缺省值，则该字段不参与计算
                if(DefaultConstant.BMS_SingleCellVolt.compareTo(lastSingle) !=0 && DefaultConstant.BMS_SingleCellVolt.compareTo(currentSingle) !=0){
                    Double volt = NumberUtil.sub(lastSingle.doubleValue(), currentSingle.doubleValue());
                    rateMap.put("rate"+i,NumberUtil.div(volt, Convert.toDouble(duration)));
                    singleCellVolts.add(((BigDecimal) lastSingleCellVolt));
                    singleCellVolts.add(((BigDecimal)currentSingleCellVolt));
                }

            }
        }
        boolean match = false;
        List<Double> rates = new ArrayList<>(0);
        if(CollectionUtil.isNotEmpty(rateMap)){
            rates = rateMap.values().stream().filter(Objects::nonNull).collect(Collectors.toList());
            //电压变化速率达到阈值
            match = rates.stream().anyMatch(rate -> {
                boolean flag=false;
                if(TermalComparisonTypeEnum.EQ.getKey()==condition){
                    NumberUtil.equals(Convert.toBigDecimal(rate), threshold);
                }
                if(TermalComparisonTypeEnum.LE.getKey()==condition){
                    NumberUtil.isLessOrEqual(new BigDecimal(rate), threshold);
                }
                if(TermalComparisonTypeEnum.LESS.getKey()==condition){
                    flag= NumberUtil.isLess(new BigDecimal(rate), threshold);
                }
                if(TermalComparisonTypeEnum.GE.getKey()==condition){
                    flag=NumberUtil.isGreaterOrEqual(new BigDecimal(rate), threshold);
                }
                if(TermalComparisonTypeEnum.GREATER.getKey()==condition){
                    flag= NumberUtil.isGreater(new BigDecimal(rate), threshold);
                }
                if(TermalComparisonTypeEnum.EXCLUDE.getKey()==condition){
                    flag = !NumberUtil.equals(new BigDecimal(rate), threshold);
                }
                return flag;
            });
        }

        if(match){
            BigDecimal[] voltArr=singleCellVolts.toArray(new BigDecimal[singleCellVolts.size()]);
            //最大电压
            BigDecimal maxSingleCellVolt=NumberUtil.max(voltArr);
            //最小电压
            BigDecimal minSingleCellVolt=NumberUtil.min(voltArr);
            //最大电压变化速率
            Double maxVoltRate=NumberUtil.max(rates.toArray(new Double[rates.size()]));
            return Dict.of(TermalProcessResult.MATCH,true,
                    TermalProcessResult.MAX_VOLTAGE,maxSingleCellVolt,
                    TermalProcessResult.MIN_VOLTAGE,minSingleCellVolt,
                    TermalProcessResult.MAX_VOLTAGE_CHANGERISE,maxVoltRate,
                    TermalProcessResult.THRESHOLD_VOLTAGE_CHANGERISE,threshold,
                    TermalProcessResult.RECENTLY_TID,recentlyTid,
                    TermalProcessResult.STRATEGY_KEY,TermalRunawayTypeEnum.VOLTAGEVARIATION.getKey(),
                    TermalProcessResult.STRATEGY_DESC,TermalRunawayTypeEnum.VOLTAGEVARIATION.getValue());
        }
        return Dict.of(TermalProcessResult.MATCH,false,
                TermalProcessResult.THRESHOLD_VOLTAGE_CHANGERISE,threshold,
                TermalProcessResult.RECENTLY_TID,recentlyTid,
                TermalProcessResult.STRATEGY_KEY,TermalRunawayTypeEnum.VOLTAGEVARIATION.getKey(),
                TermalProcessResult.STRATEGY_DESC,TermalRunawayTypeEnum.VOLTAGEVARIATION.getValue());

    }

    /**
     * 两条数据生成间隔
     *
     * @param last    上一条记录
     * @param current 当前记录
     */
    public static Long countDuration(WaringTermalWithStragegyAndFlagEv last, WaringTermalWithStragegyAndFlagEv current) {
        DateTime lastDateTime = DateUtil.date(Long.valueOf(last.getItem_time()));
        DateTime currentDateTime = DateUtil.date(Long.valueOf(current.getItem_time()));
        long duration = DateUtil.between(lastDateTime, currentDateTime, DateUnit.SECOND);
        if (duration == 0) {
            duration = 1;
        }
        return duration;
    }
}
